"""
Description:
Version: 1.0
Author: ZhangHongYu
Date: 2021-06-22 09:45:36
LastEditors: ZhangHongYu
LastEditTime: 2021-06-22 10:26:58
"""
import numpy as np
from typing import Tuple


def qr_gram_schmidt(a_: np.ndarray) -> Tuple[np.ndarray, np.ndarray]:
    n_ = a_.shape[1]
    R_ = np.zeros((n_, n_))
    Q_ = np.zeros(a_.shape)
    for j in range(n_):
        # 默认copy为深拷贝，此处y为A的一维向量切片
        y = a_[:, j].copy()
        # 生成R中对角线以上的元素
        for i in range(j):
            # R_i,j 为投影系数
            R_[i, j] = Q_[:, i].dot(a_[:, j])
            # y 为余向量
            y = y - R_[i, j] * Q_[:, i]
        R_[j, j] = np.linalg.norm(y)
        Q_[:, j] = y / R_[j, j]
    return Q_, R_


if __name__ == '__main__':
    # 前提: A中列向量线性无关
    A = np.array(
        [
            [1, -4],
            [2, 3],
            [2, 2]
        ]
    )
    Q, R = qr_gram_schmidt(A)
    print(Q, "\n\n", R)
